#include "types.h"
#include "riscv.h"
#include "proc.h"
#include "defs.h"
#include "fs/file.h"
#include "fs/fs.h"
#include "fs/stat.h"
#include "fs/fcntl.h"
#include "param.h"

// 分配文件描述符
static int
fdalloc(struct file *f)
{
  int fd;
  struct proc *p = myproc();

  if(p == 0)
    return -1;

  for(fd = 0; fd < NOFILE; fd++){
    if(p->ofile[fd] == 0){
      p->ofile[fd] = f;
      return fd;
    }
  }
  return -1;
}

// 写文件
int sys_write(void) {
  int fd, count;
  uint64 buf_addr;
  if (argint(0, &fd) < 0 || argaddr(1, &buf_addr) < 0 || argint(2, &count) < 0)
    return -1;

  struct proc *p = myproc();
  if(p == 0)
    return -1;

  // 支持标准输出（fd=1）和标准错误（fd=2）的特殊情况
  if(fd == 1 || fd == 2) {
    if(buf_addr && count > 0) {
      for(int i = 0; i < count; i++) {
        uart_putc(((char*)buf_addr)[i]);
      }
      return count;
    }
    return -1;
  }

  // 其他文件描述符需要从文件描述符表中获取
  if(fd < 0 || fd >= NOFILE || p->ofile[fd] == 0)
    return -1;

  return filewrite(p->ofile[fd], buf_addr, count);
}

// 读文件
int sys_read(void) {
  int fd, count;
  uint64 buf_addr;
  if (argint(0, &fd) < 0 || argaddr(1, &buf_addr) < 0 || argint(2, &count) < 0)
    return -1;

  struct proc *p = myproc();
  if(p == 0)
    return -1;

  // 支持标准输入（fd=0）的特殊情况
  if(fd == 0) {
    if(buf_addr && count > 0) {
      int i;
      for(i = 0; i < count; i++) {
        int c = uart_getc();
        if(c < 0) {
          // 没有数据可读
          break;
        }
        ((char*)buf_addr)[i] = (char)c;
        if(c == '\n' || c == '\r') {
          i++;
          break;
        }
      }
      return i;
    }
    return -1;
  }

  // 其他文件描述符需要从文件描述符表中获取
  if(fd < 0 || fd >= NOFILE || p->ofile[fd] == 0)
    return -1;

  return fileread(p->ofile[fd], buf_addr, count);
}

// 打开文件
int sys_open(void) {
  char path[MAXPATH];
  int fd, omode;
  struct file *f;
  struct inode *ip;
  int n;

  if((n = argstr(0, path, MAXPATH)) < 0 || argint(1, &omode) < 0)
    return -1;

  begin_op();

  if(omode & O_CREATE){
    ip = create(path, T_FILE, 0, 0);
    if(ip == 0){
      end_op();
      return -1;
    }
  } else {
    if((ip = namei(path)) == 0){
      end_op();
      return -1;
    }
    ilock(ip);
    if(ip->type == T_DIR && omode != O_RDONLY){
      iunlockput(ip);
      end_op();
      return -1;
    }
  }

  if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
    iunlockput(ip);
    end_op();
    return -1;
  }

  if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
    if(f)
      fileclose(f);
    iunlockput(ip);
    end_op();
    return -1;
  }

  if(ip->type == T_DEVICE){
    f->type = FD_DEVICE;
    f->major = ip->major;
  } else {
    f->type = FD_INODE;
    f->off = 0;
  }
  f->ip = ip;
  f->readable = !(omode & O_WRONLY);
  f->writable = (omode & O_WRONLY) || (omode & O_RDWR);

  if((omode & O_TRUNC) && ip->type == T_FILE){
    itrunc(ip);
  }

  iunlock(ip);
  end_op();

  return fd;
}

// 关闭文件
int sys_close(void) {
  int fd;
  struct file *f;

  if(argint(0, &fd) < 0)
    return -1;
  
  struct proc *p = myproc();
  if(p == 0 || fd < 0 || fd >= NOFILE)
    return -1;
  
  if((f = p->ofile[fd]) == 0)
    return -1;
  
  p->ofile[fd] = 0;
  fileclose(f);
  return 0;
}